<template>
  <div class="common__upload" :class="{ center: drag, 'hide-upload': checkExceed() }">
    <div class="upload__wrapper">
      <el-upload ref="fileUpload" action="#" :list-type="listType" :show-file-list="showFileList" :file-list="fileList" :auto-upload="false" :http-request="upload" :limit="multiple ? limit : 1" :on-change="fileChange" :accept="accept" :multiple="multiple" :drag="drag">
        <template v-if="listType === 'text'">
          <slot></slot>
        </template>
        <i v-if="listType === 'picture-card'" slot="default" class="el-icon-plus"></i>
        <template v-if="listType === 'picture-card'" slot="file" slot-scope="{ file }">
          <img v-if="determineFileType(file.name, 'image')" class="el-upload-list__item-thumbnail" :src="file.url" />
          <div v-if="determineFileType(file.name, 'file')" class="file-name">
            <span>{{ file.name }}</span>
          </div>
          <video v-if="determineFileType(file.name, 'video')" class="el-upload-list__item-thumbnail" :src="file.url"></video>
          <span class="el-upload-list__item-actions">
            <span class="el-upload-list__item-preview" @click="handlePreview(file)">
              <i class="el-icon-view"></i>
            </span>
            <span class="el-upload-list__item-delete" @click="handleDel(file)">
              <i class="el-icon-delete"></i>
            </span>
          </span>
          <div v-if="file.percentage && file.status === 'ready'" class="onupload">
            <span>{{ file.percentage }} %</span>
          </div>
        </template>
      </el-upload>
    </div>
    <div v-if="notice === true" class="warning">
      <span>
        <i class="el-icon-warning"></i>
        限制文件上传大小为 {{ maxSize / 1024 / 1024 }}M
      </span>
    </div>
    <div v-if="showFileList && listType === 'text' && fileList.length !== 0" class="file__list__wrapper">
      <div v-for="(item, index) in fileList" :key="index" class="list__item">
        <div class="left">
          <div class="file__name" :class="{ error: item.status === 'error' }">
            <span>{{ item.name }}</span>
            <i v-if="item.status === 'done'" class="el-icon-check success"></i>
          </div>
          <div v-if="item.percentage && item.status === 'ready'" class="file__progress">
            <el-progress :percentage="item.percentage" />
          </div>
          <div v-if="item.status === 'error'" class="error">
            <span>上传失败</span>
          </div>
        </div>
        <div class="right">
          <i class="el-icon-view" @click="handlePreview(item)"></i>
          <i class="el-icon-close close" @click="handleDel(item)"></i>
        </div>
      </div>
    </div>
    <FilePreview v-model="previewShow" :file="previewFile" />
  </div>
</template>
<script>
import CommonFileApi from '@/api/common-file';
import FilePreview from '@/components/FilePreview/index';
import axios from 'axios';
export default {
  components: { FilePreview },
  props: {
    url: {
      type: String,
      default: ''
    },
    fileList: {
      type: Array,
      default: () => []
    },
    showFileList: {
      type: Boolean,
      default: true
    },
    listType: {
      type: String,
      default: 'picture-card'
    },
    maxSize: {
      type: Number,
      default: 1024 * 1024 * 200
    },
    accept: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    },
    drag: {
      type: Boolean,
      default: false
    },
    limit: {
      type: Number,
      default: NaN
    },
    autoUpload: {
      type: Boolean,
      default: true
    },
    otherData: {
      type: Object,
      default: () => ({})
    },
    moduleType: {
      type: String,
      default: ''
    },
    upDownType: {
      type: String,
      default: 'FTP'
    },
    notice: {
      type: Boolean,
      default: false
    },
    autoDelete: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      previewShow: false,
      previewFile: [],
      abort: [],
      page_url: '',
      previewUrl: '',
      list: []
    };
  },
  methods: {
    determineFileType(filename, type) {
      const fileExtension = filename
        .split('.')
        .pop()
        .toLowerCase();

      if (type === 'image') {
        return ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(fileExtension);
      } else if (type === 'video') {
        return ['mp4', 'mov', 'avi', 'mkv', 'flv'].includes(fileExtension);
      } else {
        return !['jpg', 'jpeg', 'png', 'gif', 'bmp', 'mp4', 'mov', 'avi', 'mkv', 'flv'].includes(fileExtension);
      }
    },
    reset() {
      this.$refs['fileUpload'].clearFiles();
      this.fileList = [];
      for (let i = 0; i < this.abort.length; i++) {
        const element = this.abort[i];
        element();
      }
      this.abort = [];
    },
    upload(file = null) {
      const { upDownType, moduleType } = this;
      const uploadFiles = file === null ? this.fileList : [file];
      for (let i = 0; i < uploadFiles.length; i++) {
        const uploadFile = uploadFiles[i];
        const formData = new FormData();
        formData.append('file', uploadFile.raw);
        const { otherData } = this;
        Object.keys(otherData).forEach(key => {
          formData.append(key, otherData[key]);
        });
        const onUploadProgress = progressEvent => {
          let percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
          const findFileIndex = this.fileList.findIndex(item => item.uid === uploadFile.uid);
          if (findFileIndex !== -1) {
            this.fileList[findFileIndex].percentage = percentCompleted - 1;
          }
        };
        const { cancel, request } = this.uploadFile(formData, onUploadProgress);
        request
          .then(res => {
            const findFileIndex = this.fileList.findIndex(item => item.uid === uploadFile.uid);
            if (res && res.code === 200) {
              this.fileList[findFileIndex].percentage = 100;
              this.$emit('addFile', res, uploadFile);
              this.fileList[findFileIndex].status = 'done';

              this.fileList[findFileIndex].fileId = res.data.fileId;
              this.fileList[findFileIndex].fileName = res.data.fileName;
              this.fileList[findFileIndex].url = CommonFileApi.getFileUrl({
                upDownType,
                moduleType,
                fileId: res.data.fileId
              });
            } else {
              this.fileList[findFileIndex].status = 'error';
            }
          })
          .catch(_ => {
            const findFileIndex = this.fileList.findIndex(item => item.uid === uploadFile.uid);
            if (findFileIndex !== -1) {
              this.fileList[findFileIndex].status = 'error';
              this.fileList.splice(findFileIndex, 1);
            }
          });
        this.abort.push(cancel);
      }
    },
    confirm() {
      this.upload();
    },
    handlePreview(file) {
      if (file.url) {
        this.previewFile = file;
        this.previewShow = true;
      }
    },
    makePdf(url) {
      var newstr = url.replace(/%26/g, '&');
      axios.get(newstr, { responseType: 'blob' }).then(res => {
        const { data } = res;
        let binaryData = [];
        binaryData.push(data);
        let pdfUrl = '';
        pdfUrl = window.URL.createObjectURL(new Blob(binaryData, { type: 'application/pdf' }));
        this.page_url = pdfUrl;
      });
    },
    fileChange(file, fileList) {
      const { maxSize, autoUpload } = this;
      let err = false;
      if (file.raw) {
        const fileSize = file.raw.size;
        if (fileSize > maxSize) {
          this.$message({
            type: 'warning',
            message: `文件大小不能超过${maxSize / 1024 / 1024}M`
          });
          err = true;
        }
      }
      if (err) return;
      this.$emit('update:fileList', this.uniqList([...this.fileList, ...fileList]));
      if (autoUpload) {
        this.upload(file);
      }
    },
    uniqList(list) {
      let uniqueUids = new Set(list.map(item => item.uid));
      return Array.from(uniqueUids).map(uid => list.find(item => item.uid === uid));
    },
    handleDel(file) {
      this.$confirm(`是否确定删除`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
        customClass: 'myClass'
      })
        .then(() => {
          const index = this.list.findIndex(i => i.uid === file.uid);
          this.del(file, index);
        })
        .catch(_ => {});
    },
    del(file, index) {
      if (this.autoDelete) {
        this.fileList.splice(index, 1);
        this.$emit('update:fileList', this.uniqList([...this.fileList]));
      }
      this.$emit('removeFile', file);
    },
    uploadFile(data = {}, onUploadProgress) {
      const CancelToken = axios.CancelToken;
      const source = CancelToken.source();
      let sendObject = {
        cache: false,
        onUploadProgress,
        cancelToken: source.token
      };
      return {
        cancel: () => {
          source.cancel();
        },
        request: CommonFileApi.upload(this.upDownType, this.moduleType, data, sendObject)
      };
    },
    checkExceed() {
      const { multiple, limit, fileList } = this;
      const limitNum = multiple ? limit : 1;
      return fileList.length >= limitNum;
    }
  }
};
</script>
<style scoped lang="scss">
.common__upload {
  width: 100%;
  &.center {
    text-align: center;
  }
  .upload__wrapper {
    display: inline;
  }
  .warning {
    margin-top: 10px;
    color: #e6a23c;
    line-height: normal;
  }
  .img__list__wrapper {
    display: inline;
    .list__item {
      width: 90px;
      height: 90px;
      position: relative;
      overflow: hidden;
      background-color: #fff;
      border: 1px solid #c0ccda;
      border-radius: 6px;
      box-sizing: border-box;
      margin: 0 8px 8px 0;
      display: inline-block;
      img {
        object-fit: cover;
      }
    }
  }
  .file__list__wrapper {
    margin-top: 10px;
    .list__item {
      margin-bottom: 5px;
      width: 100%;
      display: flex;
      align-items: center;
      &:last-child {
        margin-bottom: 0;
      }
      .left {
        flex: 1;
        text-align: left;
        .file__name {
          display: flex;
          align-items: center;
          .success {
            color: #67c23a;
            margin-left: 10px;
          }
          &.error {
            color: #f56c6c;
          }
          span {
            display: block;
            line-height: normal;
          }
        }
        .error {
          color: #f56c6c;
          line-height: normal;
        }
      }
      .right {
        margin-left: 10px;
        font-size: 18px;
        .close {
          cursor: pointer;
          &:hover {
            color: #000;
          }
        }
      }
    }
  }
  .file-name {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px;
    box-sizing: border-box;
    line-height: normal;
    word-break: break-all;
    span {
      display: block;
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      font-weight: bold;
    }
  }
  .onupload {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    cursor: default;
    text-align: center;
    color: #fff;
    font-size: 20px;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: bold;
  }
}
.hide-upload {
  ::v-deep.el-upload--picture-card {
    display: none;
  }
}

::v-deep {
  .el-upload-list__item {
    width: 90px;
    height: 90px;
  }
  .el-upload--picture-card {
    width: 90px;
    height: 90px;
    display: inline-flex;
    justify-content: center;
    align-items: center;
  }
  .el-upload-list__item-thumbnail {
    object-fit: cover;
  }
  .el-upload-list--picture-card {
    line-height: 0;
  }
}
.preview-wrapper {
  width: 100%;
  height: 60vh;
  img,
  video {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}
::v-deep .el-upload-list__item {
  transition: none !important;
  -webkit-transition: nonne !important;
}
::v-deep .el-upload-list__item-name {
  transition: none !important;
  -webkit-transition: nonne !important;
}
</style>
